package com.order.api.service.impl;


import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.order.api.constant.OrderStateEnum;
import com.order.api.dao.OrdersDao;
import com.order.api.dao.ShopsDao;
import com.order.api.po.Orders;
import com.order.api.po.OrdersExample;
import com.order.api.po.Shops;
import com.order.api.service.OrdersService;
import com.order.api.vo.request.OrdersAddRequest;
import com.order.api.vo.request.OrdersIdRequest;
import com.order.api.vo.request.OrdersUpdateRequest;
import com.order.api.vo.request.PageRequest;
import com.order.api.vo.response.OrdersResponse;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class OrdersServiceImpl implements OrdersService {

    @Autowired
    private OrdersDao ordersDao;

    @Autowired
    private ShopsDao shopsDao;

    private String FLAG="2";

    @Autowired
    private JedisPool jedisPool;

    @Autowired
    private RedisTemplate redisTemplate;

    private static final String LOCK_SUCCESS = "OK";

    private static final String SET_IF_NOT_EXIST = "NX";

    private static final String SET_WITH_EXPIRE_TIME = "PX";

    private long EXPIRE_TIME=3000000;

   /*
    public static final String STOCK_LUA;

    static {
        */
    /**
         *
         * @desc 扣减库存Lua脚本
         * 库存（stock）-1：表示不限库存
         * 库存（stock）0：表示没有库存
         * 库存（stock）大于0：表示剩余库存
         *
         * @params 库存key
         * @return
         *      0:库存不足
         *      -1:库存未初始化
         *      大于0:剩余库存（扣减之前剩余的库存）
         *      redis缓存的库存(value)是-1表示不限库存，直接返回1
         *//*
        StringBuilder sb = new StringBuilder();
        sb.append("if (redis.call('exists', KEYS[1]) == 1) then");
        sb.append("    local stock = tonumber(redis.call('get', KEYS[1]));");
        sb.append("    if (stock == -1) then");
        sb.append("        return 1;");
        sb.append("    end;");
        sb.append("    if (stock > 0) then");
        sb.append("        redis.call('incrby', KEYS[1], -1);");
        sb.append("        return stock;");
        sb.append("    end;");
        sb.append("    return 0;");
        sb.append("end;");
        sb.append("return -1;");
        STOCK_LUA = sb.toString();
    }*/
    /**
     * @param key           库存key
     * @param expire        库存有效时间,单位秒
     * @param stockCallback 初始化库存回调函数
     * @return 0:库存不足; -1:库存未初始化; 大于0:扣减库存之前的剩余库存（扣减之前剩余的库存）
     *//*
    public long stock(String key, long expire, IStockCallback stockCallback) {
        long stock = stock(key);
        // 初始化库存
        if (stock == UNINITIALIZED_STOCK) {
            RedisLock redisLock = new RedisLock(redisTemplate, key);
            try {
                // 获取锁
                if (redisLock.tryLock()) {
                    // 双重验证，避免并发时重复回源到数据库
                    stock = stock(key);
                    if (stock == UNINITIALIZED_STOCK) {
                        // 获取初始化库存
                        final int initStock = stockCallback.getStock();
                        // 将库存设置到redis
                        redisTemplate.opsForValue().set(key, initStock, expire, TimeUnit.SECONDS);
                        // 调一次扣库存的操作
                        stock = stock(key);
                    }
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            } finally {
                redisLock.unlock();
            }

        }
        return stock;
    }
*/
    /**
     * 获取库存
     *
     * @param key 库存key
     * @return 0:库存不足; -1:库存未初始化; 大于0:剩余库存
     */
    public int getStock(String key) {
        Integer stock = (Integer) redisTemplate.opsForValue().get(key);
        return stock == null ? -1 : stock;
    }
    /**
     * 扣库存
     *
     * @param
     * @return 扣减之前剩余的库存【0:库存不足; -1:库存未初始化; 大于0:扣减库存之前的剩余库存】
     */
    /*private Long stock(String key) {
        // 脚本里的KEYS参数
        List<String> keys = new ArrayList<>();
        keys.add(key);
        // 脚本里的ARGV参数
        List<String> args = new ArrayList<>();

        long result = (long) redisTemplate.execute(new RedisCallback<Long>() {
            @Override
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                Object nativeConnection = connection.getNativeConnection();
                // 集群模式和单机模式虽然执行脚本的方法一样，但是没有共同的接口，所以只能分开执行
                // 集群模式
                if (nativeConnection instanceof JedisCluster) {
                    return (Long) ((JedisCluster) nativeConnection).eval(STOCK_LUA, keys, args);
                }

                // 单机模式
                else if (nativeConnection instanceof Jedis) {
                    return (Long) ((Jedis) nativeConnection).eval(STOCK_LUA, keys, args);
                }
                return UNINITIALIZED_STOCK;
            }
        });
        return result;
    }*/


    @Override
    public OrdersResponse findOrder(OrdersIdRequest request) {
        //判断参数
        if (request == null) {
            return new OrdersResponse();
        }
        String key = "order_" + request.getId();
        ValueOperations<String, Orders> operations = redisTemplate.opsForValue();
        //判断redis中是否存在key
        boolean hasKey = redisTemplate.hasKey(key);
        if (hasKey) {
            Orders orders = operations.get(key);
            OrdersResponse response = new OrdersResponse();
            BeanUtils.copyProperties(orders, response);
            if (orders.getState().equals(OrderStateEnum.EFFECTIVE.getKey())) {
                response.setState(OrderStateEnum.EFFECTIVE.getTitle());
            } else {
                response.setState(OrderStateEnum.INVALID.getTitle());
            }
            return response;
        } else {
            Orders orders = ordersDao.selectByPrimaryKey(request.getId());
            if (orders==null){
                return null;
            }
            operations.set(key,orders,5, TimeUnit.HOURS);
            OrdersResponse response = new OrdersResponse();
            BeanUtils.copyProperties(orders, response);
            if (orders.getState().equals(OrderStateEnum.EFFECTIVE.getKey())) {
                response.setState(OrderStateEnum.EFFECTIVE.getTitle());
            } else {
                response.setState(OrderStateEnum.INVALID.getTitle());
            }
            return response;
        }
    }

    @Override
    public PageInfo<OrdersResponse> findOrderList(PageRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        OrdersExample example = new OrdersExample();
        List<Orders> orders = ordersDao.selectByExample(example);
        List<OrdersResponse> list=new ArrayList<>();
        for (Orders order : orders) {
            OrdersResponse response = new OrdersResponse();
            BeanUtils.copyProperties(order,response);
            if (order.getState().equals(OrderStateEnum.EFFECTIVE.getKey())){
                response.setState(OrderStateEnum.EFFECTIVE.getTitle());
            }else {
                response.setState(OrderStateEnum.INVALID.getTitle());
            }
            list.add(response);
        }
        return new PageInfo<>(list);
    }

    @Override
    public boolean addOrder(OrdersAddRequest request) {
        boolean flag = false;
        switch (FLAG){
            //走mysql
            case "1":
                flag = addOrderByMysql(request);
                break;
            //走redis
            case "2":
                flag = addOrderByRedis(request);
                break;
        }
        return flag;
    }
    //利用redis保证数据准确性//如何使用redis
    private boolean addOrderByRedis(OrdersAddRequest request){

        //判断参数
        if (null==request){
            return false;
        }
        long time = new Date().getTime();

        //从redis中查询剩余库存
        ValueOperations<String, Shops> operations=redisTemplate.opsForValue();
        String key="shop_"+request.getShopId();

        Jedis jedis = null;
        jedis = jedisPool.getResource();
        String result = jedis.set(key,String.valueOf(request.getShopId()) , SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME,EXPIRE_TIME );
        System.out.println(result+"result-----------");
        if (LOCK_SUCCESS.equals(result)) {


            boolean hasKey = redisTemplate.hasKey(key);
            if (hasKey) {
                System.out.println(key+"key----------");
                Shops shops = (Shops)operations.get(key);
                if (request.getOrderQuantity() > shops.getCommodityQuantity()) {
                    return false;
                } else {
                    //删除商品原有缓存
                    redisTemplate.delete(key);
                    shops.setCommodityQuantity(shops.getCommodityQuantity() - request.getOrderQuantity());
                    //设置商品库存新缓存
                    operations.set(key, shops, 5, TimeUnit.HOURS);
                    return true;
                }
            } else {
                return false;
            }
        }else {
            return false;
        }

    }
    //mysql保证数据准确性
    private boolean addOrderByMysql(OrdersAddRequest request){
        int count = 1;
        Orders orders = new Orders();
        //订单对应的商品的信息
        Shops shops = shopsDao.selectByPrimaryKey(request.getShopId());
        //订单商品数量与商品库存数量对比
        if (request.getOrderQuantity()>shops.getCommodityQuantity()){
            return false;
        }else {
            BeanUtils.copyProperties(request,orders);
            //修改后的数量
            int total = shops.getCommodityQuantity() - request.getOrderQuantity();
            //确保数据正确性,判断商品数量与之前查询的商品数量相等
            int i = shopsDao.updateShopsTotal(request.getShopId(), total, shops.getCommodityQuantity());
            if (i!=count){
                //利用递归解决用户未抢到锁，显示数量足够却显示操作失败？
                return false;
            }
            return count== ordersDao.insertSelective(orders);
        }


    }

    @Override
    public boolean updateOrder(OrdersUpdateRequest request) {
        int count = 1;
        Orders orders = new Orders();
        BeanUtils.copyProperties(request, orders);
        //订单对应的商品的信息
        Shops shops = shopsDao.selectByPrimaryKey(request.getShopId());
        //订单商品数量与商品库存数量对比
        if (request.getOrderQuantity() > shops.getCommodityQuantity()) {
            return false;
        } else {
            BeanUtils.copyProperties(request, orders);
            //修改后的数量
            int total = shops.getCommodityQuantity() - request.getOrderQuantity();
            //确保数据正确性,判断商品数量与之前查询的商品数量相等
            int i = shopsDao.updateShopsTotal(request.getShopId(), total, shops.getCommodityQuantity());
            if (i!=count){
                return false;
            }
            return count == ordersDao.updateByPrimaryKey(orders);
        }
    }

    @Override
    public boolean deleteOrder(OrdersIdRequest request) {
        if (request==null){
            return false;
        }
        int count = ordersDao.deleteByPrimaryKey(request.getId());
        if (count!=0){
            String key="order_"+request.getId();
            boolean haskey = redisTemplate.hasKey(key);
            if (haskey) {
                redisTemplate.delete(key);
            }
        }
        return count== 1;
    }
}
